function WP_OnEvent()
	WP_Debug(WP_debugEvents, "Received event: "..event)

	if event == "ADDON_LOADED" and arg1 == "WoWPro" then
		WP_Message("WoWPro Addon Loaded")
		WP_SetGuide(WP_currentType, WP_currentGuideID, WP_currentStep)

	elseif event == "CHAT_MSG_SYSTEM" then
		if arg1 then _,_,questg = string.find(arg1, "Quest accepted: (.+)") end
		if questg then WP_CheckQuestGetEvent(questg) end
		
		if arg1 then _,_,questt = string.find(arg1, "(.+) completed.") end
		if questt then WP_CheckQuestTurnEvent(questt) end
		
		if arg1 then _,_,lochome = string.find(arg1, "(.+) is now your home.") end
		if lochome then WP_CheckBindEvent(lochome) end
		
	elseif event == "CHAT_MSG_LOOT" then 
		if arg1 then _,_, loot = string.find(arg1, "%[(.-)%]") end
		if loot then WP_CheckLootEvent(loot) end
		
	elseif event == "COMBAT_LOG_EVENT_UNFILTERED" then
		if arg4 == UnitName("player") and arg2 == "PARTY_KILL" then WP_CheckKillEvent(arg7) end
		
	elseif event == "QUEST_LOG_UPDATE" then
		WP_CheckQuestEvent()	
		
	elseif event == "ZONE_CHANGED" or event == "ZONE_CHANGED_INDOORS" or event == "ZONE_CHANGED_NEW_AREA" then
		WP_CheckZoneEvent()

	elseif event == "PLAYER_LEVEL_UP" then
		if arg1 then
			WP_CheckXPEvent(arg1)
		else
			local level = UnitLevel("player")
			WP_CheckXPEvent(level)
		end
		
	elseif event == "PLAYER_XP_UPDATE" then
		local level = UnitLevel("player")
		WP_CheckXPEvent(level)
	
	elseif event == "MERCHANT_SHOW" or event == "GOSSIP_SHOW" or event == "TRAINER_SHOW"
		or event == "TAXIMAP_OPENED" then
		WP_CheckSpeakEvent()
		if event == "TRAINER_SHOW" then WP_CheckTrainEvent() end
		if event == "TAXIMAP_OPENED" then WP_CheckTaxiEvent() end

	elseif event == "UPDATE_FACTION" then
		WP_CheckReputationEvent()
	end
end 


function WP_RegisterStepEvents(msg)
	msg = WP_RegisterQuest(msg)
	msg = WP_RegisterQuestGetEvent(msg)
	msg = WP_RegisterQuestTurnEvent(msg)
	msg = WP_RegisterCoordsEvent(msg)
	msg = WP_RegisterLootEvent(msg)
	msg = WP_RegisterKillEvent(msg)
	msg = WP_RegisterZoneEvent(msg)
	msg = WP_RegisterBindEvent(msg)
	msg = WP_RegisterXPEvent(msg)
	msg = WP_RegisterTaxiEvent(msg)
	msg = WP_RegisterReputationEvent(msg)
	msg = WP_RegisterRepairEvent(msg)
	msg = WP_RegisterSpeakEvent(msg)
	msg = WP_RegisterTrainEvent(msg)
	msg = WP_RegisterSkillEvent(msg)
end 

---------------------------- QUEST EVENT ----------------------------

function WP_RegisterQuest(msg)
	local _,_,f1 = string.find(msg, "<regQuest=(.-)>")
	
	if f1 then
		local _,_,f2,f3 = string.find(f1, "(.+)=(%d+)")
	
		if f2 and f3 then
			WP_Debug(WP_debugQuests, "Registering watch of step "..f3.." of the quest '"..f2.."'")
			table.insert(WP_currentEvents,{"Q2",f2,f3,false})
			msg = string.gsub(msg, "<regQuest=.-="..f3..">","",1)
			f2,f3 = nil
			WP_RegisterQuest(msg)
		else
			WP_Debug(WP_debugQuests, "Registering watching the quest '"..f1.."'")
			table.insert(WP_currentEvents,{"Q",f1,false})
			msg = string.gsub(msg, "<regQuest=.->","",1)
			f1 = nil
			WP_RegisterQuest(msg)
		end
	end
	return msg
end

function WP_CheckQuestEvent()
	local numEntries = GetNumQuestLogEntries()
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "Q" then
			for i = 1, numEntries, 1 do
				local title,_,_,_,_,_,complete = GetQuestLogTitle(i)		
				if complete and title == v[2] then
					WP_Debug(WP_debugQuests, "Full quest completion condition for quest '"..v[2].."'")
					v[3] = true
					WP_CheckAllEvents()
				end
			end
			
		elseif v[1] == "Q2" then
			for i = 1, numEntries, 1 do
				local title = GetQuestLogTitle(i)
				if title == v[2] then
					local _,_, done = GetQuestLogLeaderBoard (v[3],i)
					if done then 
						WP_Debug(WP_debugQuests, "Partial quest completion condition for step "..v[3].." of quest '"..v[2].."'")
						v[4] = true
						WP_CheckAllEvents()
					end
				end	 -- if title == v[2] then			
			end -- for i = 1, numEntries, 1 do
		end -- elseif v[1] == "Q2" then
	end -- for k,v in pairs(WP_currentEvents) do
end


----------------------------- QUEST GET EVENT -------------------------

function WP_RegisterQuestGetEvent(msg)
	local _,_,f1 = string.find(msg, "<regGet=(.-)>")
	if f1 ~= nil then 
		WP_Debug(WP_debugQuests, "Registering quest get event for quest '"..f1.."'")
		table.insert(WP_currentEvents,{"G",f1,false})
		msg,num = string.gsub(msg, "<regGet=.->","",1)
		WP_RegisterQuestGetEvent(msg)
		f1 = nil
	end
	return msg
end 

function WP_CheckQuestGetEvent(quest)
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "G" and v[2] == quest then
			WP_Debug(WP_debugQuests, "Got the quest '"..quest.."'")
			v[3] = true
			WP_CheckAllEvents()
		end
	end
end 

----------------------------- QUEST TURN IN EVENT -------------------------

function WP_RegisterQuestTurnEvent(msg)
	local _,_,f1 = string.find(msg, "<regTurn=(.-)>")
	if f1 then
		WP_Debug(WP_debugQuests, "Registering quest turn event for quest '"..f1.."'")
		table.insert(WP_currentEvents,{"T",f1,false})
		msg = string.gsub(msg, "<regTurn=.->","",1)
		f1 = nil
		WP_RegisterQuestTurnEvent(msg)
	end
	return msg
end 

function WP_CheckQuestTurnEvent(quest)
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "T"  and v[2] == quest then
			WP_Debug(WP_debugQuests, "Turned in the quest '"..quest.."'")
			v[3] = true
			WP_CheckAllEvents()
		end
	end
end 

----------------------------- COORDS EVENT -------------------------

function WP_RegisterCoordsEvent(msg)
	if string.find(msg, "<regCoords>") then 
		WP_Debug(WP_debugCoords, "Registering event for reaching coordinates")
		table.insert(WP_currentEvents,{"C",false})
		msg = string.gsub(msg, "<regCoords>", "",1)
	end
	return msg
end 

function WP_CheckCoordsEvent()
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "C" then
			WP_Debug(WP_debugCoords, "Reached certain coordinates")
			v[2] = true;
			WP_CheckAllEvents()
		end
	end
end 

----------------------------- LOOT EVENT -------------------------

function WP_RegisterLootEvent(msg)
	_,_,f1,f2 = string.find(msg, "<regLoot=(.-)=(%d*)>")
	if f1 and f2 then
		WP_Debug(WP_debugLoot, "Registering event for looting "..f2.." ["..f1.."]")
		table.insert(WP_currentEvents,{"L",f1,tonumber(f2),false})
		msg = string.gsub(msg, "<regLoot=.-="..f2..">", "", 1)
		f1,f2 = nil
		WP_RegisterLootEvent(msg)
	end
	return msg
end 

function WP_CheckLootEvent(loot)
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "L" and v[2] == loot then
			if (GetItemCount(v[2]) + 1) >= v[3] and v[4] == false then
				WP_Debug(WP_debugLoot, "Have looted "..v[3].." ["..v[2].."]")
				v[4] = true
				WP_CheckAllEvents()
			end
		end
	end
end

function WP_CheckAllLootEvents()
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "L" then
			if GetItemCount(v[2]) >= v[3] and v[4] == false then
				WP_Debug(WP_debugLoot, "Checked looting "..v[3].." ["..v[2].."]")
				v[4] = true
			end
		end
	end
	
	WP_CheckAllEvents()
end

----------------------------- KILL EVENT -------------------------

function WP_RegisterKillEvent(msg)
	local _,_,f1,f2 = string.find(msg, "<regKill=(.-)=(%d*)>")
	if f1 and f2 then
		WP_Debug(WP_debugKills, "Registering kill event for "..f2.." of "..f1)
		table.insert(WP_currentEvents,{"K",f1,tonumber(f2),0,false})
		msg = string.gsub(msg, "<regKill=.-="..f2..">","",1)
		f1,f2 = nil
		WP_RegisterKillEvent(msg)
	end
	return msg
end 

function WP_CheckKillEvent(dead)
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "K" and v[2] == dead then
			v[4] = v[4] + 1
			if v[4] >= v[3] then
				WP_Debug(WP_debugKills, "Killed "..v[3].." of "..v[2])
				v[5] = true
				WP_CheckAllEvents()
			end
		end
	end
end 

----------------------------- ZONE EVENT -------------------------

function WP_RegisterZoneEvent(msg)
	local _,_,f1 = string.find(msg, "<regZone=(.-)>")
	if f1 then 
		WP_Debug(WP_debugZones, "Registering event for zoning into '"..f1.."'")
		table.insert(WP_currentEvents,{"Z",f1,false})
		msg = string.gsub(msg, "<regZone=.->","",1)
		f1 = nil
		WP_RegisterZoneEvent(msg)
	end
	return msg
end 


function WP_CheckZoneEvent()
	local zone = GetZoneText()
	local subzone = GetSubZoneText()
	if subzone == "" then subzone = zone end
	local fullzone = zone .. ":" .. subzone

	for k,v in pairs(WP_currentEvents) do
		if v[1] == "Z" and (v[2] == zone or v[2] == subzone or v[2] == fullzone) then
			WP_Debug(WP_debugZones, "Zoned into '"..v[2].."'")
			v[3] = true
			WP_CheckAllEvents()
		end
	end
end

----------------------------- BIND EVENT -------------------------

function WP_RegisterBindEvent(msg)
	local _,_,f1 = string.find(msg, "<regBind=(.-)>")
	if f1 then
		WP_Debug(WP_debugBinds, "Registering event for binding at "..f1)
		table.insert(WP_currentEvents,{"B",f1,false})
		msg = string.gsub(msg, "<regBind=.->", "", 1)
		f1 = nil
		WP_RegisterBindEvent(msg)
	end
	return msg
end

function WP_CheckBindEvent(lochome)
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "B" and v[2] == lochome  then
			WP_Debug(WP_debugBinds, "Bound at "..v[2])
			v[3] = true
			WP_CheckAllEvents()
		end
	end
end

------------------------------ XP EVENT --------------------------

function WP_RegisterXPEvent(msg)
	local _,_,f1 = string.find(msg, "<regXP=(.-)>")
	
	if f1 then
		local _,_,f2,f3 = string.find(f1, "(%d+)=-(%d+)")
	
		if f2 and f3 then
			WP_Debug(WP_debugXP, "Registering grind until "..f3.." xp below level "..f2)
			table.insert(WP_currentEvents,{"X2",f2,-f3,false})
			msg = string.gsub(msg, "<regXP="..f2.."=-"..f3..">","",1)
			f2,f3 = nil
			WP_RegisterXPEvent(msg)
		else
			_,_,f2,f3 = string.find(f1, "(%d+)=(%d+)")
			if f2 and f3 then
				WP_Debug(WP_debugXP, "Registering grind until "..f3.." xp above level "..f2)
				table.insert(WP_currentEvents,{"X2",f2,f3,false})
				msg = string.gsub(msg, "<regXP="..f2.."="..f3..">","",1)
				f2,f3 = nil
				WP_RegisterXPEvent(msg)
			else
				WP_Debug(WP_debugXP, "Registering grind until level "..f1)
				table.insert(WP_currentEvents,{"X",f1,false})
				msg = string.gsub(msg, "<regXP="..f1..">","",1)
				f1 = nil
				WP_RegisterXPEvent(msg)
			end
		end
	end
	return msg
end

function WP_CheckXPEvent(lvl)
	local curXP = UnitXP("player")
	local maxXP = UnitXPMax("player")
	
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "X" then
			v[2] = v[2] + 0
			if lvl >= v[2] then
				WP_Debug(WP_debugXP, "Reached level "..v[2])
				v[3] = true
				WP_CheckAllEvents()
			end
		
		elseif v[1] == "X2" then
			v[2] = v[2] + 0
			v[3] = v[3] + 0
			if v[3] >= 0 then
				if (lvl == v[2] and curXP >= v[3]) or (lvl > v[2]) then
					WP_Debug(WP_debugXP, "Reached "..v[3].." xp above level "..v[2])
					v[4] = true
					WP_CheckAllEvents()
				end
			
			else
				local reqXP = maxXP + v[3]
				local reqLvl = v[2] - 1
				
				if (lvl == reqLvl and curXP >= reqXP) or (lvl > v[2]) then
					WP_Debug(WP_debugXP, "Reached "..-v[3].." xp to level"..v[2])
					v[4] = true
					WP_CheckAllEvents()
				end
			end
		end
	end
end

----------------------------- TAXI EVENT -------------------------

function WP_RegisterTaxiEvent(msg)
	local _,_,f1 = string.find(msg, "<regFlight=(.-)>")
	if f1 then
		WP_Debug(WP_debugFlight, "Registering event to get flight path at "..f1)
		table.insert(WP_currentEvents,{"F",f1,false})
		msg = string.gsub(msg, "<regFlight=.->", "", 1)
		f1 = nil
		WP_RegisterTaxiEvent(msg)
	end
	return msg
end

function WP_CheckTaxiEvent()
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "F" then
			WP_Debug(WP_debugFlight, "Checking for flight path at "..v[2])
			local numNodes = NumTaxiNodes()
			
			for i = 1,numNodes do
				local taxiType = TaxiNodeGetType(i)
				local taxiName = TaxiNodeName(i)
				
				_, _, name = string.find(taxiName, "(.+),.+")
				if not name then name = taxiName end
				
				WP_Debug(WP_debugFlight, "Comparing against "..name.." (of type '"..taxiType.."')")
				if taxiType == "CURRENT" and name == v[2] then
					WP_Debug(WP_debugFlight, "Got flight path at "..v[2])
					v[3] = true
					WP_CheckAllEvents()
				end
			end
		end
	end
end

-------------------------- REPUTATION EVENT ----------------------

function WP_RegisterReputationEvent(msg)
	_,_,f1,f2 = string.find(msg, "<regFaction=(.-)=(%d*)>")
	if f1 and f2 then
		WP_Debug(WP_debugReputation, "Registering event for minimum reputation "..f2.." for faction "..f1)
		table.insert(WP_currentEvents,{"R2",f1,tonumber(f2),false})
		msg = string.gsub(msg, "<regFaction=.-="..f2..">", "", 1)
		f1,f2 = nil
		WP_RegisterReputationEvent(msg)
	end
	return msg
end 

function WP_CheckReputationEvent()
	local checked = false
	
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "R2" and v[4] == false then
			local collapsedFactions = {}
			local numFactions = GetNumFactions()
			local prevNumFactions = numFactions
			local factionExpanded = false

			repeat
				factionExpanded = false
				prevNumFactions = numFactions
				for i = 1,numFactions do
					if not factionExpanded then
						name, description, standingId, bottomValue, topValue, earnedValue, atWarWith,
							canToggleAtWar, isHeader, isCollapsed, hasRept, isWatched,
							isChild = GetFactionInfo(i)
					
						if isCollapsed then
							table.insert(collapsedFactions, 1, i)
							ExpandFactionHeader(i)
							factionExpanded = true
						end
					end
				end
				numFactions = GetNumFactions()
			until numFactions == prevNumFactions
		
			for i = 1,numFactions do
				name, description, standingId, bottomValue, topValue, earnedValue, atWarWith,
					canToggleAtWar, isHeader, isCollapsed, hasRept, isWatched, isChild = GetFactionInfo(i)
			
				if v[2] == name and earnedValue >= v[3] then
					v[4] = true
					checked = true
				end
			end
		
			for k,v in pairs(collapsedFactions) do
				CollapseFactionHeader(v)
			end
		end
	end
	
	if checked then WP_CheckAllEvents() end
end

---------------------------- REPAIR EVENT ------------------------

function WP_RegisterRepairEvent(msg)
	if string.find(msg, "<regRepair>") then 
		WP_Debug(WP_debugRepair, "Registering event for repairs")
		table.insert(WP_currentEvents,{"R",false})
		msg = string.gsub(msg, "<regRepair>", "",1)
	end
	return msg
end

function WP_CheckRepairEvent()
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "R" then
			WP_Debug(WP_debugRepair, "Checking for having performed repairs")
		
			local needRepair = false
		
			local slotNames = {"Head", "Shoulder", "Chest", "Wrist", "Hands", "Waist", "Legs", "Feet",
				"MainHand", "SecondaryHand", "Ranged"}
		
			for k,v in pairs(slotNames) do
				slotId = GetInventorySlotInfo(v.."Slot")
			
				if (GetInventoryItemTexture("player", slotId)) then
					local dur, maxDur = GetInventoryItemDurability(slotId)
					if dur < maxDur then
						WP_Debug(WP_debugRepair, "Item in the '"..v.."Slot' still needs repairs")
						needRepair = true
					end
				end
			end
	
			if not needRepair then
				v[2] = true
				WP_CheckAllEvents()
			end
		end
	end
end

------------------------------- SPEAK EVENT ---------------------------

function WP_RegisterSpeakEvent(msg)
	local _,_,f1 = string.find(msg, "<regSpeak=(.-)>")
	if f1 ~= nil then 
		WP_Debug(WP_debugSpeak, "Registering speaking with '"..f1.."'")
		table.insert(WP_currentEvents,{"S",f1,false})
		msg,num = string.gsub(msg, "<regSpeak=.->","",1)
		WP_RegisterSpeakEvent(msg)
		f1 = nil
	end
	return msg
end 

function WP_CheckSpeakEvent()
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "S" and UnitName("npc") == v[2] then
			WP_Debug(WP_debugSpeak, "Speaking with '"..v[2].."'")
			v[3] = true
			WP_CheckAllEvents()
		end
	end
end 

------------------------------- TRAIN EVENT ---------------------------

function WP_RegisterTrainEvent(msg)
	if string.find(msg, "<regTrain>") then 
		WP_Debug(WP_debugTrain, "Registering event for training")
		table.insert(WP_currentEvents,{"T2",false})
		msg = string.gsub(msg, "<regTrain>", "",1)
	end
	return msg
end 

function WP_CheckTrainEvent()
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "T2" then
			WP_Debug(WP_debugTrain, "Training window opened")
			v[2] = true
			WP_CheckAllEvents()
		end
	end
end 

----------------------------- SKILL EVENT -------------------------

function WP_RegisterSkillEvent(msg)
	local _,_,f1 = string.find(msg, "<regSkill=(.-)>")
	if f1 then
		msg = string.gsub(msg, "<regSkill=.->", "", 1)
		_, _, f2, f3 = string.find(f1, "(.+)=(.+)")
		if f2 and f3 then
			WP_Debug(WP_debugSkills, "Registering skill event for rank "..f3.." of skill "..f2)
			table.insert(WP_currentEvents, {"S3",f2,f3,false})
		else
			WP_Debug(WP_debugSkills, "Registering skill event for skill "..f1)
			table.insert(WP_currentEvents, {"S2",f1,false})
		end
		f1 = nil
		WP_RegisterSkillEvent(msg)
	end
	return msg
end

function WP_CheckSkillEvent()
	for k,v in pairs(WP_currentEvents) do
		if v[1] == "S2" or v[1] == "S3" then
			name, rank = v[2], nil
			if v[1] == "S3" then rank = v[3] end
			
			numTabs = GetNumSpellTabs()
			for i = 1,numTabs do
				_, _, offset, numSpells = GetSpellTabInfo(i)
			
				for j = 1,numSpells do
					sName, sRank = GetSpellInfo(offset + j)
				
					if name == sName then
						if not rank or (rank and rank >= sRank) then
							if rank then v[4] = true else v[3] = true end
							WP_CheckAllEvents()
						end
					end
				end
			end
		end
	end
end

-----------------------------------------------------

function WP_CheckAllEvents()
	local checked = false
	
	for k,v in pairs(WP_currentEvents) do
		checked = true
		if v[1] == "Q" and v[3] == false then return end -- regQuest=quest
		if v[1] == "Q2" and v[4] == false then return end -- regQuest=quest=step
		if v[1] == "K" and v[5] == false then return end -- regKill=mob=num
		if v[1] == "L" and v[4] == false then return end -- regLoot=item=num
		if v[1] == "G" and v[3] == false then return end -- regGet=quest
		if v[1] == "T" and v[3] == false then return end -- regTurn=quest
		if v[1] == "C" and v[2] == false then return end -- regCoords
		if v[1] == "Z" and v[3] == false then return end -- regZone=loc
		if v[1] == "B" and v[3] == false then return end -- regBind=loc
		if v[1] == "X" and v[3] == false then return end -- regXP=level
		if v[1] == "X2" and v[4] == false then return end -- regXP=level=xp
		if v[1] == "F" and v[3] == false then return end -- regFlight=loc
		if v[1] == "R2" and v[4] == false then return end -- regReputation=faction=rep
		if v[1] == "R" and v[2] == false then return end -- regRepair
		if v[1] == "S" and v[3] == false then return end -- regSpeak=npc
		if v[1] == "T2" and v[2] == false then return end -- regTrain
		if v[1] == "S2" and v[3] == false then return end -- regSkill=skill
		if v[1] == "S3" and v[4] == false then return end -- regSkill=skill=rank
	end

	if checked then WP_NextStep() end
end 